package cumeo89.chii.client.wikt;

import static cumeo89.chii.client.entry.Constants.*;

import com.google.gwt.xml.client.Document;
import com.google.gwt.xml.client.Element;
import com.google.gwt.xml.client.XMLParser;

import cumeo89.chii.client.util.JSStringArray;
import cumeo89.chii.client.util.MyArrays;
import cumeo89.chii.client.util.ReplaceDelegate;
import cumeo89.chii.client.util.StringUtil;

final class WikitextParser {

	private WikitextParser() {
	}

	private static String join(String start, String end, JSStringArray... arrs) {
		StringBuffer sb = new StringBuffer(start);
		for (JSStringArray arr : arrs) {
			sb.append("|").append(arr.join("|"));
		}
		sb.append("|").append(end);
		return sb.toString();
	}

	private static final String LANGUAGE_PS = join("\\s*\r?\n?\\{\\{-(",
			")-\\}\\}\\s*", getLanguageCodes());

	private static final String HEADER2_PS = join("\\s*\r?\n?\\{\\{-(",
			")-\\}\\}\\s*", getPosCodes(), getLangSpecCodes());

	private static final String POS_RELATED_PS = join("\\s*\r?\n?\\{\\{-(",
			")-\\}\\}\\s*", getPosSpecCodes());

	private static final String INTERWIKI_PS = join("\\s*\\[\\[\\s*(",
			")\\s*:(?:.+)\\]\\]\\s*", getInterwikiPrefixes());

	private static final String TRANS_LIST_PS = join(
			"(?:^|\r?\n)\\*\\s*\\{\\{(", ")\\}\\}\\s*:?", getLanguageCodes());

	public static Document parse(String title, String wikitext) {
		Document doc = XMLParser.createDocument();
		Element root = parseRoot(doc, sanitate(wikitext));
		root.setAttribute("title", title);
		doc.appendChild(root);
		return doc;
	}

	private static String sanitate(String s) {
		s = StringUtil.replaceAll(s, "(\\{\\{)(\\w+)(\\}\\})",
				new ReplaceDelegate() {

					public String getReplacementOf(JSStringArray a) {
						int index = getRedirectKeys().binarySearch(a.get(2));
						return index < 0 ? a.get(0) : a.get(1)
								+ getRedirectValues().get(index) + a.get(3);
					}
				});
		// after chang top --> đầu,...
		s = s.replaceAll("\\{\\{(?:đầu|giữa|cuối)\\}\\}", "");
		return s;
	}

	private static native JSStringArray getRedirectKeys() /*-{
		return ["-Thành ngữ-","-abbr-","-abbreviation-","-adverb-","-af-","-ar-","-bs-","-ca-","-chia-","-cs-","-da-","-danh từ-","-de-","-dut-","-el-","-en-","-eo-","-es-","-et-","-etym-","-eu-","-exp-","-fa-","-fi-","-fo-","-fr-","-fy-","-ga-","-gl-","-gn-","-hani-","-he-","-hi-","-hr-","-hu-","-ia-","-id-","-int-pronoun-","-interr-adj-","-is-","-it-","-ja-","-jap-","-ko-","-ku-","-la-","-liên từ-","-mr-","-ms-","-mt-","-nb-","-ne-","-nl-","-nl1ps-","-nn-","-no-","-note-","-oc-","-particle-","-pl-","-pl-noun-","-pre-","-proper-","-propernoun-","-pt-","-ro-","-ru-","-rum-","-sk-","-sn-","-sq-","-suf-","-sv-","-sw-","-th-","-thành ngữ-","-thán từ-","-tr-","-tt-","-tính từ-","-từ nguyên-","-vi-","-vi-Hant-","-vi-n-","-vie-Hant-","-vie-nom-","-zh-","-đồng nghĩa-","-động từ-","@ARG","@AUS","@Achentina","@Australia","@BRA","@Ba Tây","@Ba tây","@Ba-tây","@Brazil","@Bồ đào nha","@Bồ-đào-nha","@CHI","@COL","@CUB","@Chi Lê","@Chi Lợi","@Chi lê","@Chi-lê","@Chilê","@Cu Ba","@Cu ba","@Cu-ba","@ENG","@ESP","@Econ","@FRA","@Hoa Kì","@Hoa Kỳ","@Hoa kì","@Hoa kỳ","@I Pha Nho","@I pha nho","@I-pha-nho","@MEX","@Mê Hi Cô","@Mê hi cô","@Mê-hi-cô","@Mêhicô","@Mễ Tây Cơ","@Mễ tây cơ","@Mễ-tây-cơ","@Mỹ La Tinh","@Mỹ La tinh","@Mỹ La-tinh","@PER","@POR","@Perú","@Quebec","@SCO","@Scốt-len","@Scốtlen","@Tây ban nha","@Tây-ban-nha","@Tô Cách Lan","@Tô cách lan","@Tô-cách-lan","@U.S.","@US","@USA","@Xcốt-len","@Xcốtlen","@Y Pha Nho","@Y pha nho","@Y-pha-nho","@anh","@argentina","@aus","@brasil","@brazil","@chile","@colombia","@econ","@fig","@hoa kì","@hoa kỳ","@kinh tế","@lit","@mexico","@mỹ","@nghĩa bóng","@nghĩa rộng","@nghĩa xấu","@nghĩa đen","@peru","@pháp","@quebec","@québec","@sco","@scotland","@toán","@usa","@Á Căn Đình","@Á căn đình","@Á-căn-đình","@Ác-hen-ti-na","@Áchentina","@Ê cốt","@Ê-cốt","@Ôx-trây-li-a","@Ôxtrâylia","@Úc Đại Lợi","@Úc đại lợi","@Úc-đại-lợi","@ê cốt","@ê-cốt","@úc","Af","An","Ang","Ar","Audio","Az","Be","Bg","Bgclr","Br","Ca","Catmore","Chính tả","Chờ xoá","Cite book","Click","Coord","Copyvio","Cs","Cy","Da","Danh tá»« riêng","Danh từ","Danh từ riêng","De","Delete","Dz","Dịch","El","En","Eo","Es","Et","Eu","F","Fa","Fi","Fj","Fr","Fy","Ga","Giải thích về","Gu","He","Hi","Hiddencat","Hr","Hu","Hy","Ia","Id","Inclusion","Is","It","Ja","Ka","Km","Ko","Ku","Kw","LKCL","LKTB","La","Link FA","Lt","Lv","M","Mi","Mk","Mn","Mr","Ms","Mt","Mục từ viết nổi bật","N","Ne","Ngày kỷ niệm 04-04","Ngày kỷ niệm/03/5","Nl","No","Nói về","Oc","PD","PVCC","Pl","Plur","Pt","R:Encarta","R:Kōjien","R:WordNet","Ro","Ru","Sai chính tả","Sk","Sl","Smn","So","Spelling","Sq","Sr","Stub","Sv","Sw","Switch","Sơ khai","Ta","Th","Theo chủ đề","Thiếu thông tin giấy phép","Thể loại đổi hướng","Thử","Thử (xin để yên dòng này!)","Tl","Tr","Tt","Twi","Tựa sai","Uk","Unicode hoá","Unknown","Unsigned","Unverified","Ur","User de","User de-1","User en","User en-3","User en-4","User es-1","User es-2","User fr","User fr-2","User fr-4","User it-1","User ja-0","User nl","User ru","User ru-1","User vi","User vi-0","User vi-2","Vi","Vo","Vot","Vô danh","Wen","WfD","Wfd","Wiki hóa","Wikimedia","Wiktionary:Thống kê bản dịch hàng tháng","Wrongtitle","Yi","ZHsism","Zh","Zu","abbr of","abbrev of","af","alt of","alt spelling of","alternate pages","alternate spelling of","am","an","ar","audio","az","be","bg","bottom","br","bs","ca","chú thích sách","chất lượng kém","chất lượng kém (nguồn)","chờ xoá","chờ xóa","cite book","click","conj-fr","cs","cv","cy","da","de","delete","di chuyển đến Wikibooks","dut","dz","el","en","en-adj","en-adv","en-noun","en-pr-noun","en-proper noun","en-suffix","en-verb","eng-verb/getPres3ndSgArch","eo","es","es-verb-ar","es-verb-decir","es-verb-ir","et","etym-abbrev","etym-possibly","eu","fa","fi","fj","fo","fr","fy","ga","gl","gn","gu","he","hi","hiddencat","hr","hr-decl-noun","hr-decl-noun-a-an-fa","hr-noun","hr-noun-a-an-fa","hu","hu-noun","hy","hình tượng","hình tượng URL","hình tượng url","ia","id","ie","imgexists","io","is","it","it-noun","ja","jap-prefix","jpn-prefix","jv","ka","kh","km","kn","ko","ku","kw","la","lb","li","lktb","lt","lv","lỗi tiêu bản","mi","mid","mk","ml","mr","ms","mt","na","nb","ne","nl","nl-biến danh","nl-biến danh 0","nl-biến danh 1","nl-biến danh 2","nl-biến danh 3","nl-biến danh cả","nl-biến ngôi","nl-biến ngôi-1","nl-biến ngôi-st","nl-biến phó","nl-biến tính","nl-biến tính 0","nl-biến tính 1","nl-biến tính-không cấp","nl-đại từ","nn","no","nôm char","oc","oj","past part of","pi","pl","plur-of","plural-of","pr-noun","present progressive of","pron-CA","pt","ro","ru","rum","sa","sai chính tả","sc","se","sk","sl","sn","so","spa-adj-c-cons","spa-noun.reg-cons","spa-verb-ver","spa-verb.-ie-ue-.zar","spelling","sq","sr","su","sv","sv-noun","sv-noun-un","sv-noun-unc-irreg-c","sw","swe-noun-un","sơ khai","số nhiều của","ta","te","th","thiếu giấy phép","thành viên bis","thể loại ẩn","thử/3","thử/4","tl","top","tr","truncint","tt","uk","unknown","unsigned","ur","user en","user vi-0","vi","vo","wa","wfd","wiki hoá","wo","wrongtitle","xh","xong","yi","zh","zh-rad","zh-sc","zh-sn","zh-t","zh-tc","zh-yue","zho-yue","zu","Âm thanh"];	
	}-*/;

	private static native JSStringArray getRedirectValues() /*-{
		return ["-idiom-","-abr-","-abr-","-adv-","-afr-","-ara-","-bos-","-cat-","-forms-","-ces-","-dan-","-noun-","-deu-","-nld-","-ell-","-eng-","-epo-","-spa-","-est-","-etymology-","-eus-","-expr-","-fas-","-fin-","-fao-","-fra-","-fry-","-gle-","-glg-","-grn-","-Hani-","-heb-","-hin-","-hrv-","-hun-","-ina-","-ind-","-interrog-","-interrog-","-isl-","-ita-","-jpn-","-jpn-","-kor-","-kur-","-lat-","-prep-","-mar-","-msa-","-mlt-","-nob-","-nep-","-nld-","-nlđtn1-","-nno-","-nor-","-dfn-","-oci-","-part-","-pol-","-place-","-prefix-","-pr-noun-","-pr-noun-","-por-","-ron-","-rus-","-ron-","-slk-","-sna-","-sqi-","-suffix-","-swe-","-swa-","-tha-","-idiom-","-interj-","-tur-","-tat-","-adj-","-etymology-","-vie-","-vie-n-","-vie-n-","-vie-n-","-vie-n-","-zho-","-syn-","-verb-","@Argentina","@Úc","@Argentina","@Úc","@Brasil","@Brasil","@Brasil","@Brasil","@Brasil","@Bồ Đào Nha","@Bồ Đào Nha","@Chile","@Colombia","@Cuba","@Chile","@Chile","@Chile","@Chile","@Chile","@Cuba","@Cuba","@Cuba","@Anh","@Tây Ban Nha","@kinh tế học","@Pháp","@Mỹ","@Mỹ","@Mỹ","@Mỹ","@Tây Ban Nha","@Tây Ban Nha","@Tây Ban Nha","@Mexico","@Mexico","@Mexico","@Mexico","@Mexico","@Mexico","@Mexico","@Mexico","@Mỹ Latinh","@Mỹ Latinh","@Mỹ Latinh","@Peru","@Bồ Đào Nha","@Peru","@Québec","@Scotland","@Scotland","@Scotland","@Tây Ban Nha","@Tây Ban Nha","@Scotland","@Scotland","@Scotland","@Mỹ","@Mỹ","@Mỹ","@Scotland","@Scotland","@Tây Ban Nha","@Tây Ban Nha","@Tây Ban Nha","@Anh","@Argentina","@Úc","@Brasil","@Brasil","@Chile","@Colombia","@kinh tế học","@bóng","@Mỹ","@Mỹ","@kinh tế học","@đen","@Mexico","@Mỹ","@bóng","@rộng","@xấu","@đen","@Peru","@Pháp","@Québec","@Québec","@Scotland","@Scotland","@toán học","@Mỹ","@Argentina","@Argentina","@Argentina","@Argentina","@Argentina","@Scotland","@Scotland","@Úc","@Úc","@Úc","@Úc","@Úc","@Scotland","@Scotland","@Úc","afr","arg","ang","ara","âm thanh","aze","bel","bul","bgclr","bre","cat","Liên kết bài chủ đề","chính tả","Chờ xóa","Chú thích sách","Hình tượng","coord","Vi phạm bản quyền","ces","cym","dan","-pr-noun-","-noun-","-pr-noun-","deu","Chờ xóa","dzo","-trans-","ell","eng","epo","spa","est","eus","f","fas","fin","fij","fra","fry","gle","Giới thiệu Wikipedia","guj","heb","hin","Thể loại ẩn","hrv","hun","hye","ina","ind","Bàn cãi giá trị","isl","ita","jpn","kat","khm","kor","kur","cor","Liên kết chọn lọc","Liên kết tiêu bản","lat","Liên kết chọn lọc","lit","lav","m","mri","mkd","mon","mar","msa","mlt","Mục từ viết chọn lọc","n","nep","Ngày_kỷ_niệm_4-04","Ngày_kỷ_niệm_5-03","nld","nor","Giới thiệu Wikipedia","oci","Phạm vi công cộng","Phạm vi công cộng","pol","plur","por","R:MSED","R:Kojien","R:WordNet 2006","ron","rus","chính tả","slk","slv","smn","som","chính tả","sqi","srp","stub","swe","swa","switch","stub","tam","tha","Chuyên ngành","Thiếu giấy phép","Đổi hướng thể loại","thử","thử (xin để yên dòng này!)","tgl","tur","tat","twi","tựa sai","ukr","Unicode hóa","Thiếu giấy phép","vô danh","Thiếu giấy phép","urd","User deu","User deu-1","User eng","User eng-3","User eng-4","User spa-1","User spa-2","User fra","User fra-2","User fra-4","User ita-1","User jap-0","User nld","User rus","User rus-1","User vie","User vie-0","User vie-2","vie","vol","vot","vô danh","wen","Chờ xóa","Chờ xóa","wiki hóa","CopyrightByWikimedia","Thống kê bản dịch hàng tháng","tựa sai","yid","ZHsim","zho","zul","abbreviation of","abbreviation of","afr","alternative spelling of","alternative spelling of","trang tương tự","alternative spelling of","amh","arg","ara","âm thanh","aze","bel","bul","cuối","bre","bos","cat","Chú thích sách","Chất lượng kém","Chất lượng kém (nguồn)","Chờ xóa","Chờ xóa","Chú thích sách","Hình tượng","conj-fra-mid","ces","chv","cym","dan","deu","Chờ xóa","Di chuyển đến Wikibooks","nld","dzo","ell","eng","eng-adj","eng-adv","eng-noun","eng-pr-noun","eng-pr-noun","eng-suffix","eng-verb","eng-verb/getPres3rdSgArch","epo","spa","spa-verb-ar","spa-verb-decir","spa-verb-ir","est","etym-abbr","etym-possibly-from","eus","fas","fin","fij","fao","fra","fry","gle","glg","grn","guj","heb","hin","Thể loại ẩn","hrv","hrv-noun","hrv-noun-a-an-fa","hrv-noun","hrv-noun-a-an-fa","hun","hun-noun","hye","Hình tượng","Hình tượng URL","Hình tượng URL","ina","ind","ile","imgexist","ido","isl","ita","ita-noun","jpn","zho-prefix","zho-prefix","jav","kat","khm","khm","kan","kor","kur","cor","lat","ltz","lim","Liên kết tiêu bản","lit","lav","Lỗi tiêu bản","mri","giữa","mkd","mal","mar","msa","mlt","nau","nob","nep","nld","nld-biến danh","nld-biến danh 0","nld-biến danh 1","nld-biến danh 2","nld-biến danh 3","nld-biến danh cả","nld-biến ngôi","nld-biến ngôi-1","nld-biến ngôi-st","nld-biến phó","nld-biến tính","nld-biến tính 0","nld-biến tính 1","nld-biến tính-không cấp","nld-đại từ","nno","nor","Nôm char","oci","oji","past participle of","pli","pol","plural of","plural of","-pr-noun-","present participle of","pron-ca","por","ron","rus","ron","san","chính tả","srd","sme","slk","slv","sna","som","spa-adj-neut-cons","spa-noun-reg-cons","spa-verb-er (ver)","spa-verb-zar (ie-ue)","chính tả","sqi","srp","sun","swe","swe-noun","swe-noun-unc-irreg-c","swe-noun-unc-irreg-c","swa","swe-noun-unc-irreg-c","stub","plural of","tam","tel","tha","Thiếu giấy phép","Thành viên bis","Thể loại ẩn","thử","thử/2","tgl","đầu","tur","Truncint","tat","ukr","Thiếu giấy phép","vô danh","urd","User eng","User vie-0","vie","vol","wln","Chờ xóa","wiki hóa","wol","tựa sai","xho","Xong","yid","zho","zho-rad","Hans","zho-sn","zho-t","Hant","yue","yue","zul","âm thanh"];
	}-*/;

	private static Element parseRoot(Document doc, String text) {
		Element root = doc.createElement(E_ENTRY);

		JSStringArray arrCats = StringUtil.extract(text,
				"\\s*\\[\\[\\s*Thể[ _]loại\\s*:\\s*(.+?)\\s*\\]\\]\\s*");
		JSStringArray arrInters = StringUtil.extract(arrCats.get(0),
				INTERWIKI_PS);
		JSStringArray arrLangs = StringUtil
				.split(arrInters.get(0), LANGUAGE_PS);

		if (arrLangs.get(0).length() > 0) {
			JSStringArray arrInfo = StringUtil.extract(arrLangs.get(0),
					"\\{\\{-info-\\}\\}");
			if (arrInfo.length() > 1) {
				root.setAttribute("info", "yes");
				root.appendChild(doc.createTextNode(arrInfo.get(0)));
			}
		}

		Element langs = doc.createElement(E_LANG_LIST);
		for (int i = 1; i < arrLangs.length() - 1; i += 2) {
			langs.appendChild(parseLang(doc, arrLangs.get(i), arrLangs
					.get(i + 1)));
		}
		root.appendChild(langs);

		Element cats = doc.createElement(E_CATEGORY_LIST);
		for (int i = 1; i < arrCats.length(); i++) {
			Element cat = doc.createElement(E_CATEGORY);
			cat.setAttribute(A_CATEGORY_NAME, arrCats.get(i));
			cats.appendChild(cat);
		}
		root.appendChild(cats);

		Element inters = doc.createElement(E_INTERWIKI_LIST);
		for (int i = 1; i < arrInters.length(); i++) {
			Element inter = doc.createElement(E_INTERWIKI);
			inter.setAttribute(A_INTERWIKI_LANG, arrInters.get(i));
			inters.appendChild(inter);
		}
		root.appendChild(inters);

		return root;
	}

	private static Element parseLang(Document doc, String code, String text) {
		Element lang = doc.createElement(E_LANG);
		lang.setAttribute(A_LANG_CODE, code);

		JSStringArray a = StringUtil.split(text, HEADER2_PS);
		lang.appendChild(doc.createTextNode(a.get(0)));

		for (int j = 1; j < a.length() - 1; j += 2) {
			code = a.get(j);
			text = a.get(j + 1);

			if ("etymology".equals(code)) {
				code = "etym";
			}

			if (MyArrays.contains(getPosCodes(), code)) {
				lang.appendChild(parsePos(doc, code, text));
			} else if (MyArrays.contains(RELATED_WORDS_CODES, code)) {
				lang.appendChild(parseWordList(doc, code, text));
			} else if ("pron".equals(code) || "etym".equals(code)
					|| "translit".equals(code)) {
				Element e = doc.createElement(code);
				e.appendChild(doc.createTextNode(text));
				lang.appendChild(e);
			} else {
				throw new IllegalArgumentException();
			}
		}

		return lang;
	}

	private static Element parsePos(Document doc, String code, String text) {
		Element pos = doc.createElement(E_POS);
		pos.setAttribute("code", code);

		JSStringArray arrRel = StringUtil.split(text, POS_RELATED_PS);
		JSStringArray arrDef = StringUtil.split(arrRel.get(0),
				"\r?\n\\s*#(?!:)");

		pos.setAttribute(A_POS_SPELL, arrDef.get(0));

		Element defs = doc.createElement(E_DEF_LIST);
		for (int i = 1; i < arrDef.length(); i++) {
			String text2 = arrDef.get(i).trim();
			if (text2.length() > 0) {
				defs.appendChild(parseDefinition(doc, arrDef.get(i)));
			}
		}
		pos.appendChild(defs);

		for (int i = 1; i < arrRel.length(); i += 2) {
			String code2 = arrRel.get(i), text2 = arrRel.get(i + 1);
			if (MyArrays.contains(RELATED_WORDS_CODES, code2)) {
				pos.appendChild(parseWordList(doc, code2, text2));
			} else if ("expr".equals(code2) || "proverb".equals(code2)
					|| "phrase".equals(code2)) {
				pos.appendChild(parseExpression(doc, text2));
			} else if (E_TRANS.equals(code2)) {
				pos.appendChild(parseTranslation(doc, text2));
			} else if ("usage".equals(code2) || "forms".equals(code2)
					|| "ref".equals(code2)) {
				appendElement(doc, pos, code2, text2);
			} else {
				throw new UnsupportedOperationException();
			}
		}

		return pos;
	}

	private static Element parseExpression(Document doc, String text) {
		Element expr = doc.createElement("expr");
		JSStringArray a = StringUtil.split(text, "\r?\n\\s*\\*(?!#)");
		for (int j = 1; j < a.length(); j++) {
			expr.appendChild(parseExpressionItem(doc, a.get(j)));
		}// FIXME
		return expr;
	}

	private static Element parseExpressionItem(Document doc, String text) {
		Element item = doc.createElement(E_EXPRESSION);

		int colonIndex = text.indexOf(':');
		if (colonIndex < 0) {
			item.setAttribute("content", text);
		} else {
			item.setAttribute("content", text.substring(0, colonIndex).replace(
					"'", "").trim());
			JSStringArray a = StringUtil.split(text.substring(colonIndex + 1),
					"\r?\n\\s*\\*#(?!:)");
			Element defs = doc.createElement(E_DEF_LIST);
			for (int i = 0; i < a.length(); i++) {
				String text2 = a.get(i).trim();
				if (text2.length() > 0) {
					defs.appendChild(parseDefinition(doc, text2));
				}
			}
			item.appendChild(defs);
		}
		return item;
	}

	private static Element parseDefinition(Document doc, String text) {
		Element def = doc.createElement(E_DEF);

		JSStringArray arrEx = StringUtil.split(text, "\r?\n\\s*\\*?#:");
		JSStringArray arrTerm = StringUtil.extract(arrEx.get(0),
				"\\{\\{\\s*term\\s*\\|([^}]+)\\}\\}");

		if (arrTerm.length() > 1) {
			Element terms = doc.createElement("terms");
			for (int i = 1; i < arrTerm.length(); i++) {
				for (String s : arrTerm.get(i).split(";|,")) {
					Element term = doc.createElement("term");
					term.setAttribute(A_CONTEXT_TEXT, s);
					terms.appendChild(term);
				}
			}
			def.appendChild(terms);
		}

		def.setAttribute(A_DEF_CONTENT, arrTerm.get(0).trim());

		if (arrEx.length() > 1) {
			Element exs = doc.createElement(E_EXAMPLE_LIST);
			for (int i = 1; i < arrEx.length(); i++) {
				exs.appendChild(parseExample(doc, arrEx.get(i)));
			}
			def.appendChild(exs);
		}

		return def;
	}

	private static Element parseExample(Document doc, String text) {
		text = text.replaceAll("\\s+", " ");
		int index = text.indexOf('—'); // dash
		if (index < 0) {
			index = text.indexOf('-'); // minus
		}
		Element ex = doc.createElement(E_EXAMPLE);
		if (index >= 0) {
			ex.setAttribute("content", text.substring(0, index).trim());
			ex
					.setAttribute(A_EXAMPLE_EXPLAIN, text.substring(index + 1)
							.trim());
		} else {
			ex.setAttribute("content", text);
		}
		return ex;
	}

	private static Element parseWordList(Document doc, String code, String text) {
		Element list = doc.createElement("wlist");
		list.setAttribute("code", code);
		JSStringArray a = StringUtil.split(text, "(?:^|\r?\n)\\s*;");
		if (a.length() == 1) {
			list.appendChild(parseSublist(doc, text));
		} else {
			list.appendChild(doc.createTextNode(a.get(0)));
			for (int i = 1; i < a.length(); i++) {
				list.appendChild(parseSublist(doc, a.get(i)));
			}
		}
		return list;
	}

	private static Element parseSublist(Document doc, String text) {
		Element sub = doc.createElement(E_SUBLIST);
		JSStringArray a = StringUtil.split(text, "(?:^|\r?\n)\\s*\\*");
		sub.setAttribute("title", a.get(0));
		for (int i = 1; i < a.length(); i++) {
			Element item = doc.createElement(E_ITEM);
			item.setAttribute("content", a.get(i).trim());
			sub.appendChild(item);
		}
		return sub;
	}

	private static Element parseTranslation(Document doc, String text) {
		Element trans = doc.createElement(E_TRANS);
		JSStringArray a = StringUtil.split(text, "(?:^|\r?\n)\\s*;(.+?)\r?\n");
		if (a.length() == 1) {
			trans.appendChild(parseTranslationSublist(doc, "", text));
		} else {
			trans.appendChild(doc.createTextNode(a.get(0)));
			for (int i = 1; i < a.length(); i += 2) {
				trans.appendChild(parseTranslationSublist(doc, a.get(i), a
						.get(i + 1)));
			}
		}
		return trans;
	}

	private static Element parseTranslationSublist(Document doc, String title,
			String text) {
		JSStringArray a = StringUtil.split(text, TRANS_LIST_PS);
		Element sub = doc.createElement(E_SUBLIST);
		sub.setAttribute("title", title);
		for (int i = 1; i < a.length(); i += 2) {
			Element item = doc.createElement(E_ITEM);
			item.setAttribute("lang", a.get(i));
			item.setAttribute("content", a.get(i + 1).trim());
			sub.appendChild(item);
		}
		return sub;
	}

	private static void appendElement(Document doc, Element parent, String tag,
			String value) {
		Element element = doc.createElement(tag);
		element.appendChild(doc.createTextNode(value));
		parent.appendChild(element);
	}

}
